package com.gzsxy.esjy.gateway.config;

import cn.hutool.core.collection.CollectionUtil;
import com.gzsxy.esjy.common.base.exception.impl.BusinessException;
import com.gzsxy.esjy.service.base.dto.response.DefaultResponse;
import com.gzsxy.esjy.common.base.util.ReflectUtil;

import com.gzsxy.esjy.redis.user.AuthContants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;

import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;

import java.net.ConnectException;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author xiaolong
 * @version 1.0
 * @description: gateway自定义异常处理
 * @date 2021/12/17 20:14
 */
public class RmcloudExceptionHandler extends DefaultErrorWebExceptionHandler {


    private final static Logger log = LoggerFactory.getLogger("api_log");


    public RmcloudExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }

    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
        int status = 200;
        int code = 200;
        DefaultResponse response = new DefaultResponse();
        Throwable error = super.getError(request);
        String message = error.getMessage();
        if (error instanceof ResponseStatusException){
            code = ((ResponseStatusException)error).getStatus().value();
        } else if (error instanceof NotFoundException){
            code = 404;
            if (message != null){
                String[] fors = message.split("for");
                String msg = fors.length >1 ? fors[fors.length-1] :message;
                message = "连接服务器异常:"+msg;
            }else {
                message = "连接服务器异常";
            }
        } else if (error instanceof BusinessException){
            BusinessException ex = (BusinessException)error;
            code = ex.getExceptionCode();
            message = ex.getMessage();
        } else if (error instanceof ConnectException){
            code = HttpStatus.SERVICE_UNAVAILABLE.value();
            message = "连接服务器异常";
        }
        if (code == 200){
            code = 500;
        }
        response.setCode(code);
        response.setMsg(message);
        response.setLevel(0);

        Optional<Object> attribute = request.attribute(AuthContants.REQUEST_ID);
        String requestId = "未知";
        if (attribute != Optional.empty()){
            requestId = attribute.get().toString();
        }else {
            List<String> header = request.headers().header(AuthContants.REQUEST_ID);
            if (CollectionUtil.isNotEmpty(header)){
                requestId = header.get(0);
            }
        }
        return response(response,status);
    }

    /**
     * @description: 指定响应处理方法为json处理的方法
     * @param
     * @return
     */
    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(),this::renderErrorResponse);
    }

    /**
     * @description: 根据code获取对应的httpstatus
     * @param
     * @return
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {
        int statusCode = (int) errorAttributes.get("status");
        return statusCode;
    }

    /**
     * @description: 构建返回的JSON数据格式
     * @param
     * @return
     */
    public static Map<String,Object> response(DefaultResponse response,int status){
        Map<String, Object> map = ReflectUtil.convertBeanToMap(response);
        map.put("status",status);
        return map;
    }

}
